package rtype

import (
	"reflect"
	"unsafe"
)

// SizeoRtype Rtype占用大小
var SizeoRtype = uintptr(unsafe.Sizeof(Rtype{}))

// PtrSize unsafe.Sizeof(uintptr(0)) but an ideal const
const PtrSize = 4 << (^uintptr(0) >> 63)

// Flag 类型
type Flag uintptr

const (
	FlagKindWidth        = 5 // there are 27 kinds
	FlagKindMask    Flag = 1<<FlagKindWidth - 1
	FlagStickyRO    Flag = 1 << 5
	FlagEmbedRO     Flag = 1 << 6
	FlagIndir       Flag = 1 << 7
	FlagAddr        Flag = 1 << 8
	FlagMethod      Flag = 1 << 9
	FlagMethodShift      = 10
	FlagRO          Flag = FlagStickyRO | FlagEmbedRO
)
const (
	KindDirectIface = 1 << 5
	KindGCProg      = 1 << 6 // Type.gc points to GC program
	KindMask        = (1 << 5) - 1
)

// Kind 类型
//go:linkname (Flag).Kind reflect.(flag).kind
func (f Flag) kind() reflect.Kind

// Ro 内部函数
////go:linkname (Flag).Ro reflect.(flag).ro
func (f Flag) Ro() Flag

// Tflag 额外值类型信息
type Tflag uint8

// Nameoff 名称偏移
type Nameoff int32

// Typeoff 类型偏移
type Typeoff int32

// Rtype 底层类型
type Rtype struct {
	Size       uintptr
	Ptrdata    uintptr // number of bytes in the type that can contain pointers
	Hash       uint32  // hash of type; avoids computation in hash tables
	Tflag      Tflag   // extra type information flags
	Align      uint8   // alignment of variable with this type
	Fieldalign uint8   // alignment of struct field with this type
	KindC      uint8   // enumeration for C
	// function for comparing objects of this type
	// (ptr to object A, ptr to object B) -> ==?
	Equal     func(unsafe.Pointer, unsafe.Pointer) bool
	Gcdata    *byte   // garbage collection data
	Str       Nameoff // string form
	PtrToThis Typeoff // type for pointer to this type, may be zero
}

// Kind 类型
//go:linkname (*Rtype).Kind reflect.(*rtype).Kind
func (t *Rtype) Kind() reflect.Kind

// Name 自定义类型名称
//go:linkname (*Rtype).Name reflect.(*rtype).Name
func (t *Rtype) Name() string

// PkgPath 类型所在包路径
//go:linkname (*Rtype).PkgPath reflect.(*rtype).PkgPath
func (t *Rtype) PkgPath() string

// NumMethod 得到方法总数
//go:linkname (*Rtype).NumMethod reflect.(*rtype).NumMethod
func (t *Rtype) NumMethod() int

// Flag 类型标记
func (t *Rtype) Flag() Flag {
	f := Flag(t.Kind())
	if t.KindC&KindDirectIface == 0 {
		f |= FlagIndir
	}
	return f
}

// TypeName 得到类型名称
func (t *Rtype) TypeName() (name string) {
	return t.Kind().String()
}
